/*
 
 TopMind jLynx "jLynx JDBC Framework"
 Copyright (c) 2004-2007. TopMind Systems Inc.
 All rights reserved.
 
 This file is part of TopMind jLynx.
 
 TopMind jLynx is free software; you can redistribute it and/or modify
 it under the terms of the License. See website for License.
 
 */
package net.sf.jlynx;

import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * <p>
 * Generates JavaBean style objects (POJOs) and JSPs based on database tables &
 * fields.
 * 
 * <p>
 * $Id: Generator.java 99 2007-06-21 02:51:13Z gritc11 $
 * 
 */
public final class Generator {

	static Logger logger = LoggerFactory.getLogger(Generator.class);

	static int tableCount = 0;

	static int progress = 0;

	static StringBuffer e = new StringBuffer("");

	public static String generateCode(String packageName, String schema,
			String srcdir, String superClass) throws Exception {

		Relational r = RelationalFactory.getInstance();
		logger.debug("init " + r.getClass());
		r = null;
		if (!ConfigParser.isParsed)
			return "No code generated. Check jlynx.xml!";

		StringBuffer out = new StringBuffer();

		if ("".equals(schema))
			schema = null;

		e = new StringBuffer();

		if (false) {
			System.out.println(srcdir);
			return null;
		}

		if (superClass == null)
			superClass = "";
		else
			superClass = " extends " + superClass;

		String suffix = "Bean";

		StringTokenizer st = new StringTokenizer(packageName, ".");
		String path = "";
		while (st.hasMoreTokens())
			path += File.separator + st.nextToken();

		path += File.separator;

		out.append("\n\nTimestamp: " + new Date());

		File srcDir = new File(srcdir + File.separator + "src" + File.separator
				+ path);

		File classes = new File(srcdir + File.separator + "classes");
		File jspDir = new File(srcdir + File.separator + "jsp");

		// create src or classes dirs
		classes.mkdirs();
		srcDir.mkdirs();
		jspDir.mkdirs();

		out.append("\n\nJSP files will be generated in: "
				+ jspDir.getCanonicalPath());
		out
				.append("\nPOJOs will be compiled in: "
						+ classes.getCanonicalPath());
		out.append("\nPOJO source directory: " + srcDir.getCanonicalPath()
				+ "\n");

		out.append("\nJDBC Driver: " + ConfigParser.getDriver());
		out.append("\nJDBC URL: " + ConfigParser.getUrl());
		out.append("\nJDBC User: " + ConfigParser.getUsername());

		String javaCode = "";
		StringBuffer jspCode = new StringBuffer("");

		String accessors = "";
		String flds = "";
		if (schema != null)
			out.append("\nFiltering on schema: " + schema);

		Set tables = SchemaUtil.getTables(null, schema).keySet();

		tableCount = tables.size();
		progress = 0;

		Iterator iter = tables.iterator();
		int count = 0;
		while (iter.hasNext()) {
			count++;
			progress++;
			String table = (String) iter.next();
			boolean create = true;
			Map fields = SchemaUtil.getColumns(table);
			String className = StringUtils.mixedCase(table);// + suffix;

			javaCode = "// Java code generated by TopMind jLynx on "
					+ new Date() + "\n\n";
			jspCode = new StringBuffer();

			String msg = "<!-- ** JSP code generated by jLynx on " + new Date()
					+ " ** -->\n\n";

			jspCode.append(msg + "<fieldset>\n<legend> " + table
					+ " Form </legend>" + "\n<form action='' method='post'>\n");

			if (packageName != null && !"".equals(packageName)) {
				javaCode += "package " + packageName + ";\n\n";
				jspCode
						.append("\t<input type='hidden' name='bean.class' value='"
								+ packageName + "." + className + "'/>\n");

			} else
				jspCode
						.append("\t<input type='hidden' name='bean.class' value='"
								+ className + "'/>\n");
			jspCode
					.append("<div class='field'>\n\t<input type='submit' value='Submit form'/>\n</div>");

			e.append("  <entity class='" + packageName + "." + className
					+ "' name='" + table.toLowerCase() + "' />\n");

			StringBuffer j5 = new StringBuffer(javaCode);
			j5.append("import javax.persistence.*;\n\n@Entity\n@Table(name=\""
					+ table + "\")\n");
			j5.append("public class " + className + suffix
					+ " implements java.io.Serializable {");
			javaCode += "public class " + className + superClass
					+ " implements java.io.Serializable {";

			accessors = "";
			flds = "";
			String flds2 = "";
			Map pk = SchemaUtil.getPrimaryKeys(table);

			if (pk.size() == 0) {

				String wrng = "Warning: Table <<"
						+ table
						+ ">> does not have a primary key defined! jLynx requires a primary key.";
				out.append(wrng);

			}

			Iterator iter2 = SchemaUtil.getColumns(table).keySet().iterator();
			String id = "";
			while (iter2.hasNext()) {
				String field = (String) iter2.next();
				logger.debug(field);
				logger.debug("pk=" + pk);
				Iterator pkIter = pk.keySet().iterator();
				while (pkIter.hasNext()) {
					String pkValue = pkIter.next().toString();
					if (pkValue.equalsIgnoreCase(field)) {
						id = "\n\n    @Id @Column(name=\"" + field + "\")";
						break;
					} else
						id = "\n\n    @Column(name=\"" + field + "\")";
				}
				accessors += StringUtils.createAccessor(field, (String) fields
						.get(field));// name,type

				flds += "\n\n    private " + (String) fields.get(field) + " "
						+ field + ";";

				flds2 += id + " private " + (String) fields.get(field)
						+ " " + field + ";";

				jspCode.append("\n<div class='field'>\n\t<label for='bean."
						+ field + "'>" + field + "</label>");

				jspCode.append("\n\t<input type='text' name='bean." + field
						+ "' value='${bean." + field + "}'/>\n</div>");

			}

			jspCode.append("\n</form>\n</fieldset>\n");

			javaCode += flds + accessors + "\n\n}";
			j5.append(flds2 + accessors + "\n\n}");

			String fileName = srcDir.getCanonicalPath() + File.separator
					+ className + ".java";

			if (create) {
				out.append("\n\nCreating.... " + fileName);

				File file = new File(fileName);
				if (file.canRead() == false && file.createNewFile()) {
					FileOutputStream fout = new FileOutputStream(file);
					fout.write(new String(javaCode.toString()).getBytes());
					fout.flush();
					fout.close();
					fileName = srcDir.getCanonicalPath() + File.separator
							+ className + suffix + ".java";
					out.append("\nCreating.... " + fileName);
					file = new File(fileName);
					fout = new FileOutputStream(file);
					fout.write(new String(j5.toString()).getBytes());
					fout.flush();
					fout.close();

				} else {
					file = null;
					System.out
							.println("Did not create file... source file already exists");
				}

				// System.out.println(e.toString());

				// write a jsp file now
				// System.out.println(jspCode);
				File file2 = new File(jspDir.getCanonicalPath()
						+ File.separator + table + ".jsp.html");
				if (file2.exists() == false && file2.createNewFile()) {
					FileOutputStream fout2 = new FileOutputStream(file2);
					fout2.write(new String(jspCode).getBytes());
					fout2.flush();
					fout2.close();
					out.append("\nCreated JSP: " + file2.getCanonicalPath());
				} else
					out.append("\nCannot create JSP... file exists");

				if (true)
					return out.toString();

				// try compiling now
				try {

					String[] args = new String[] { "-classpath", "-g", "-d",
							classes.getCanonicalPath(), fileName };
					out.append("\nCompiling... " + fileName);
					// System.out.println("Compiling... " + args);
					ClassLoader.getSystemClassLoader().loadClass(
							"com.sun.tools.javac.Main");
					com.sun.tools.javac.Main.compile(args, new PrintWriter(
							System.out));

				} catch (ClassNotFoundException cfne) {
					out.append("\nError compiling :: Class Not Found... "
							+ cfne.getMessage());
				}

			}

		}

		return out.toString();
	}
}